package com.common.utils;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.time.temporal.WeekFields;
import java.util.Date;

public class LocalDateUtils {

    public static int calcMinusDays(int tradeDate, int days){
        LocalDate localDate = transferLocalDate(tradeDate);
        localDate = localDate.minusDays(days);
        return transferYYYYMMDD(localDate);
    }

    public static int calcPlusDays(int tradeDate, int days){
        LocalDate localDate = transferLocalDate(tradeDate);
        localDate = localDate.plusDays(days);
        return transferYYYYMMDD(localDate);
    }

    public static LocalDateTime getLastTimeFromTradeDate(int tradeDate){
        LocalDate localDate = transferLocalDate(tradeDate);
        return LocalDateTime.of(localDate, LocalTime.MAX);
    }

    public static LocalDateTime getFirstTimeFromTradeDate(int tradeDate){
        LocalDate localDate = transferLocalDate(tradeDate);
        return LocalDateTime.of(localDate, LocalTime.MIN);
    }

    public static int transferYYYYMMDD(LocalDate localDate){
        return Integer.parseInt(localDate.format(DateTimeFormatter.BASIC_ISO_DATE));
    }

    public static LocalDate transferLocalDate(int tradeDate){
        if (tradeDate <= 0){
            return null;
        }
        return LocalDate.parse(String.valueOf(tradeDate), DateTimeFormatter.BASIC_ISO_DATE);
    }

    public static long betweenDays(int d1, int d2){
        LocalDate p1 = transferLocalDate(d1);
        LocalDate p2 = transferLocalDate(d2);
        return betweenDays(p1, p2);
    }

    public static long betweenDays(LocalDate d1, LocalDate d2){
        return ChronoUnit.DAYS.between(d1,d2);
    }

    public static long betweenMonths(int d1, int d2){
        LocalDate p1 = transferLocalDate(d1);
        LocalDate p2 = transferLocalDate(d2);
        return  ChronoUnit.MONTHS.between(p1, p2);
    }

    public static long between(LocalDateTime t1, LocalDateTime t2, ChronoUnit unit){
        if (ChronoUnit.NANOS == unit){
            return unit.between(t1, t2);
        } else {
            return unit.between(t1.withNano(0), t2.withNano(0));
        }
    }

    public static int getWeekOfYear(LocalDate localDate){
        localDate = localDate==null?LocalDate.now():localDate;
        WeekFields weekFields = WeekFields.of(DayOfWeek.MONDAY,7);
        return localDate.get(weekFields.weekOfWeekBasedYear());
    }

    public static int lastDayOfMonth(int tradeDate){
        return transferYYYYMMDD(transferLocalDate(tradeDate).with(TemporalAdjusters.lastDayOfMonth()));
    }
    public static int firstDayOfNextMonth(int tradeDate){
        return transferYYYYMMDD(transferLocalDate(tradeDate).with(TemporalAdjusters.firstDayOfNextMonth()));
    }


    public static LocalDate firstDayOnMonth(LocalDate localDate){
        return localDate.with(TemporalAdjusters.firstDayOfMonth());
    }
    public static LocalDate lastDayOnMonth(LocalDate localDate){
        return localDate.with(TemporalAdjusters.lastDayOfMonth());
    }


    public static Date convertToDateViaSqlDate(LocalDate localDate) {
        return java.sql.Date.valueOf(localDate);
    }

    public static Date convertToDateViaInstant(LocalDate localDate) {
        return Date.from(localDate.atStartOfDay()
                .atZone(ZoneId.systemDefault())
                .toInstant());
    }

    public static Date convertToDateViaSqlTimestamp(LocalDateTime dateTime) {
        return java.sql.Timestamp.valueOf(dateTime);
    }

    public static Date convertToDateViaInstant(LocalDateTime dateTime) {
        return Date
                .from(dateTime.atZone(ZoneId.systemDefault())
                        .toInstant());
    }

    public static LocalDate convertToLocalDateViaInstant(Date dateToConvert) {
        return dateToConvert.toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalDate();
    }
    public LocalDate convertToLocalDateViaSqlDate(Date dateToConvert) {
        return new java.sql.Date(dateToConvert.getTime()).toLocalDate();
    }

    public static LocalDateTime convertToLocalDateTimeViaInstant(Date dateToConvert) {
        return dateToConvert.toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalDateTime();
    }
    public LocalDateTime convertToLocalDateTimeViaMilisecond(Date dateToConvert) {
        return Instant.ofEpochMilli(dateToConvert.getTime())
                .atZone(ZoneId.systemDefault())
                .toLocalDateTime();
    }

}
